package org.zero;

import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;

import java.io.IOException;
import java.util.List;

/**
 * Java agent 支持静态加载和动态加载
 * <p>
 * 静态加载：通过 vm 启动参数 -javaagent 将 agent jar 挂载到目标 JVM 程序，随其一起启动。对应的是 agentmain() 方法。
 * 其中 -javaagent 格式："-javaagent:<jarpath>[=<option>]"。
 * {@code [=<option>]}部分可以指定 agent 的参数，可以传递到{@code premain(String agentArgs, Instrumentation inst)}方法的 agentArgs 入参中。
 * 也支持可以挂载多个 agent，按指定顺序先后执行。所以不同的顺序可能会导致 agent 对类的修改存在冲突。
 * 比如：项目中同时用到了 TTL 和 SkyWalking，应该先加载 TTL，再加载 SkyWalking。
 *
 * @author zero
 * @since 2021/1/11
 */
public class AttachBootstrap {
    /**
     * 动态加载：通过 Attach API 动态地加载 Java agent。对应的是 agentmain() 方法。
     */
    public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
        List<VirtualMachineDescriptor> virtualMachineDescriptors = VirtualMachine.list();
        System.out.println(virtualMachineDescriptors);
        // VirtualMachine virtualMachine = VirtualMachine.attach(virtualMachineDescriptors.get(0));

        // 使用目标 JVM 进程 pid
        VirtualMachine virtualMachine = VirtualMachine.attach(args[0]);
        try {
            // 加载指定 agent.jar
            virtualMachine.loadAgent(args[1]);
        } finally {
            virtualMachine.detach();
        }
    }
}
